#include "bsp_clock.h"
#if (CONFIG_OS_ENABLE == 1)
#include "os_sal.h"
#endif


/* BSP-时钟驱动 */


#if defined(CONFIG_SYSTEM_FREQ_400M)
/**
* System Clock source            = PLL (HSE)
* SYSCLK(Hz)                     = 400000000 (CPU Clock)
* HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
* AHB Prescaler                  = 2
* D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
* D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
* D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
* D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
* HSE Frequency(Hz)              = 25000000
* PLL_M                          = 5
* PLL_N                          = 160
* PLL_P                          = 2
* PLL_Q                          = 4
* PLL_R                          = 2
* VDD(V)                         = 3.3
* Flash Latency(WS)              = 4
*/
#define CLOCK_PLL_M 5
#define CLOCK_PLL_N 160
#define CLOCK_PLL_P 2
#define CLOCK_PLL_Q 4

#elif defined(CONFIG_SYSTEM_FREQ_480M)
/**
* System Clock source            = PLL (HSE)
* SYSCLK(Hz)                     = 480000000 (CPU Clock)
* HCLK(Hz)                       = 240000000 (AXI and AHBs Clock)
* AHB Prescaler                  = 2
* D1 APB3 Prescaler              = 2 (APB3 Clock  120MHz)
* D2 APB1 Prescaler              = 2 (APB1 Clock  120MHz)
* D2 APB2 Prescaler              = 2 (APB2 Clock  120MHz)
* D3 APB4 Prescaler              = 2 (APB4 Clock  120MHz)
* HSE Frequency(Hz)              = 25000000
* PLL_M                          = 5
* PLL_N                          = 192
* PLL_P                          = 2
* PLL_Q                          = 4
* PLL_R                          = 2
* VDD(V)                         = 3.3
* Flash Latency(WS)              = 4
*/
#define CLOCK_PLL_M 5
#define CLOCK_PLL_N 192
#define CLOCK_PLL_P 2
#define CLOCK_PLL_Q 4

#else 
#error "system clock not define"
#endif


/* static var */
#define CLOCK_SYS_IRQ_NUM   3

static volatile uint8_t flag_ms_timeout = 0;
static volatile uint32_t delay_ms_cnt = 0;
static volatile uint32_t delay_fac_us = 0;

static void (*systick_irq_handle[CLOCK_SYS_IRQ_NUM])(void) = { NULL };

extern void lv_tick_inc(uint32_t tick_period);


/* static func */

/**
 * @brief 滴答时钟中断服务函数
 * 
 */
void SysTick_Handler(void)
{
    int i;

    HAL_IncTick();

#if (CONFIG_OS_ENABLE == 1)
    os_systick_handler();
#endif

    for (i = 0; i < CLOCK_SYS_IRQ_NUM; i++)
    {
        if (systick_irq_handle[i])
        {
            systick_irq_handle[i]();
        }
    }
    
    /* 1ms累计,仅用于delay_ms函数 */
    if (delay_ms_cnt)
    {
        if (--delay_ms_cnt == 0)
        {
            flag_ms_timeout = 1;
        }
    }

}


/* export func */

/**
 * @brief 初始化系统时钟
 * 
 */
void bsp_clock_system_init(void)
{
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0};
    HAL_StatusTypeDef ret = HAL_OK;

    /* 锁住SCU(Supply configuration update) */
    MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);

    /*
      1、芯片内部的LDO稳压器输出的电压范围，可选VOS1，VOS2和VOS3，不同范围对应不同的Flash读速度，
         详情看参考手册的Table 12的表格。
      2、这里选择使用VOS1，电压范围1.15V - 1.26V。
    */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) { }

    /* 使能HSE，并选择HSE作为PLL时钟源，配置PLL1，开启USB时钟 */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
#if (CONFIG_HW_RTC_SRC_LSI == 1)
    RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSI;
#elif #if (CONFIG_HW_RTC_SRC_LSE == 1)
    RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_LSE;
#endif
#if (CONFIG_HAL_USB_DEVICE_MODULE_ENABLED || CONFIG_HAL_USB_HOST_MODULE_ENABLED)
    RCC_OscInitStruct.OscillatorType |= RCC_OSCILLATORTYPE_HSI48;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
#endif
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
#if (CONFIG_HW_RTC_SRC_LSI == 1)
    RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
    RCC_OscInitStruct.LSIState = RCC_LSI_ON;
#elif (CONFIG_HW_RTC_SRC_LSE == 1)
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
#endif
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = CLOCK_PLL_M;
    RCC_OscInitStruct.PLL.PLLN = CLOCK_PLL_N;
    RCC_OscInitStruct.PLL.PLLP = CLOCK_PLL_P;
    RCC_OscInitStruct.PLL.PLLQ = CLOCK_PLL_Q;
    RCC_OscInitStruct.PLL.PLLR = 2;

    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
    if (ret != HAL_OK)
    {
        // Error_Handler(__FILE__, __LINE__);
    }

    /**
     * 选择PLL的输出作为系统时钟
     * 配置RCC_CLOCKTYPE_SYSCLK系统时钟
     * 配置RCC_CLOCKTYPE_HCLK 时钟，对应AHB1，AHB2，AHB3和AHB4总线
     * 配置RCC_CLOCKTYPE_PCLK1时钟，对应APB1总线
     * 配置RCC_CLOCKTYPE_PCLK2时钟，对应APB2总线
     * 配置RCC_CLOCKTYPE_D1PCLK1时钟，对应APB3总线
     * 配置RCC_CLOCKTYPE_D3PCLK1时钟，对应APB4总线
     */
    RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | \
                                    RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | \
                                    RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_D3PCLK1 );
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
    RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

    /* 此函数会更新SystemCoreClock，并重新配置HAL_InitTick */
	ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
	if (ret != HAL_OK)
	{
        // Error_Handler(__FILE__, __LINE__);
	}

	/**
     * 配置PLL2的 P=200Mhz, Q=100Mhz, R=100Mhz
     * 配置QSPI时钟源来自: HCLK3
     * 配置串口1 / 6 的时钟源来自: PCLK2
     * 配置串口2 / 3 / 4 / 5 / 7 / 8 的时钟源来自: PCLK1
     * USB工作需要48MHz的时钟,可以由PLL1Q,PLL3Q和HSI48提供,这里配置时钟源来自: HSI48
     */
    RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_RTC;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_SDMMC;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_SPI123;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_SPI45;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_USART16;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_USART234578;
    RCC_PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_USB;

    RCC_PeriphClkInit.PLL2.PLL2M = 5;
    RCC_PeriphClkInit.PLL2.PLL2N = 160;
    RCC_PeriphClkInit.PLL2.PLL2P = 4;
    RCC_PeriphClkInit.PLL2.PLL2Q = 8;
    RCC_PeriphClkInit.PLL2.PLL2R = 8;
    RCC_PeriphClkInit.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0;
    RCC_PeriphClkInit.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
    RCC_PeriphClkInit.PLL2.PLL2FRACN = 0;
    RCC_PeriphClkInit.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
#if (CONFIG_HW_RTC_SRC_LSI == 1)
    RCC_PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
#elif (CONFIG_HW_RTC_SRC_LSE == 1)
    RCC_PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
#endif
    RCC_PeriphClkInit.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL;
    RCC_PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2;
    RCC_PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2;
    RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
    RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
    RCC_PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
    ret = HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
    if (ret != HAL_OK)
    {
        // Error_Handler(__FILE__, __LINE__);
    }

    /*
      使用IO的高速模式，要使能IO补偿，即调用下面三个函数 
      （1）使能CSI clock
      （2）使能SYSCFG clock
      （3）使能I/O补偿单元， 设置SYSCFG_CCCSR寄存器的bit0
    */
	__HAL_RCC_CSI_ENABLE() ;
	__HAL_RCC_SYSCFG_CLK_ENABLE() ;
	HAL_EnableCompensationCell();

   /* AXI SRAM的时钟是上电自动使能的，而D2域的SRAM1，SRAM2和SRAM3要单独使能 */	
#if 1
	__HAL_RCC_D2SRAM1_CLK_ENABLE();
	__HAL_RCC_D2SRAM2_CLK_ENABLE();
	__HAL_RCC_D2SRAM3_CLK_ENABLE();
#endif

    delay_fac_us = SystemCoreClock / 1000000;   //节拍数
}

/**
 * @brief 滴答时钟初始化
 * 
 */
void bsp_clock_systick_init(void)
{
#if (CONFIG_OS_ENABLE == 1)
    /* OS补充 */
    uint32_t reload;

    reload = SystemCoreClock;
    reload /= CONFIG_OS_TICK_RATE_HZ;

    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;          /* 开启SYSTICK中断 */
    SysTick->LOAD = reload;                             /* 每1/configTICK_RATE_HZ秒中断一次 */
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           /* 开启SYSTICK */
#endif
    
}

void bsp_clock_systick_add_irq_handle(void (*func)(void))
{
    int i;

    for (i = 0; i < CLOCK_SYS_IRQ_NUM; i++)
    {
        if (systick_irq_handle[i] == NULL)
        {
            systick_irq_handle[i] = func;
            return ;
        }
    }
}

/**
 * @brief 获取各时钟域频率并打印
 * 
 */
void bsp_clock_disp(void)
{
    uint32_t freq;
    PLL1_ClocksTypeDef pll;

	printf("/**\r\n");
    freq = HAL_RCC_GetSysClockFreq();
    printf(" * SysClock: %dMHz\r\n", freq/1000000);

    freq = HAL_RCC_GetHCLKFreq();
    printf(" * HCLK: %dMHz\r\n", freq/1000000);

    freq = HAL_RCC_GetPCLK1Freq();
    printf(" * PCLK1: %dMHz\r\n", freq/1000000);

    freq = HAL_RCC_GetPCLK2Freq();
    printf(" * PCLK2: %dMHz\r\n", freq/1000000);

    HAL_RCCEx_GetPLL1ClockFreq(&pll);
    printf(" * PLL1: P(%dMHz), Q(%dMHz), R(%dMHz)\r\n", pll.PLL1_P_Frequency/1000000, pll.PLL1_Q_Frequency/1000000, pll.PLL1_R_Frequency/1000000);

    HAL_RCCEx_GetPLL2ClockFreq((PLL2_ClocksTypeDef*)&pll);
    printf(" * PLL2: P(%dMHz), Q(%dMHz), R(%dMHz)\r\n", pll.PLL1_P_Frequency/1000000, pll.PLL1_Q_Frequency/1000000, pll.PLL1_R_Frequency/1000000);

    HAL_RCCEx_GetPLL3ClockFreq((PLL3_ClocksTypeDef*)&pll);
    printf(" * PLL3: P(%dMHz), Q(%dMHz), R(%dMHz)\r\n", pll.PLL1_P_Frequency/1000000, pll.PLL1_Q_Frequency/1000000, pll.PLL1_R_Frequency/1000000);
	printf(" */\r\n");
}

/**
 * @brief 延时us
 * 
 * @param us 
 */
void delay_us(uint32_t us)
{
    uint32_t ticks;
    uint32_t told;
    uint32_t tnow;
    uint32_t tcnt = 0;
    uint32_t reload;

    reload = SysTick->LOAD;
    ticks = us * delay_fac_us; /* 需要的节拍数 */
    told = SysTick->VAL; /* 刚进入时的计数器值 */

    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;    //SYSTICK是一个递减的计数器
            }
            else
            {
                tcnt += reload - tnow + told;   //重新装载递减
            }
            told = tnow;

            /* 时间超过/等于要延迟的时间,则退出 */
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }
}

/**
 * @brief 延时ms
 * 
 * @param ms 
 */
void delay_ms(uint32_t ms)
{

    delay_ms_cnt = ms;
    flag_ms_timeout = 0;

    while (1)
    {
        if (flag_ms_timeout == 1)
        {
            delay_ms_cnt = 0;
            flag_ms_timeout = 0;
            break;
        }
    }
}

